package com.biscuit.page.basicservice.service;

import com.biscuit.page.basicservice.api.model.request.interview.InterviewMergeMaxFileAReq;
import com.biscuit.page.basicservice.api.model.response.interview.InterviewUploadMaxFileAResp;
import com.biscuit.page.basicservice.bean.FileMinioClient;
import com.biscuit.page.basicservice.model.enums.BaseResponseEnum;
import com.biscuit.page.basicservice.utils.BaseExceptionUtil;
import com.biscuit.page.basicservice.utils.BaseVerifyUtil;
import com.biscuit.page.basicservice.utils.FileUtil;
import com.biscuit.page.basicservice.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author biscuit
 * @createTime 2024/7/2 14:47
 */
@Slf4j
@Service
public class InterviewService {

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private FileMinioClient fileMinioClient;

    /**
     * 上传大文件（分片上传）
     *
     * @param multipartFile 文件
     * @param index         分片索引
     * @param totalPart     总分片数
     */
    public InterviewUploadMaxFileAResp uploadMaxFile(MultipartFile multipartFile, String fileName, String contentType, String uploadId, Integer index, Integer totalPart) {
        // 基于 固定业务标识、当前用户、文件名称、 获取锁
        RLock lock = this.redissonClient.getLock(RedisUtil.getLockCacheKey("filePartUpload", "admin", fileName));

        try {
            // 参数合法校验
            BaseExceptionUtil.throwException(BaseVerifyUtil.verifyNumberFullValid(totalPart), "文件分片数量异常");
            BaseExceptionUtil.throwException(Objects.nonNull(index), "文件分片索引为空");
            BaseExceptionUtil.throwException(!multipartFile.isEmpty(), "文件为空");

            // 判断文件分片大小，不足两个则不是分片上传
            BaseExceptionUtil.throwException(totalPart > 1, "文件非分片上传");

            // 尝试获取锁
            BaseExceptionUtil.throwException(lock.tryLock(0, 120, TimeUnit.SECONDS), "文件正在上传，请勿重复操作");

            // 判断是否为首次上传分片，首次需要进行分片初始化
            if (StringUtils.isBlank(uploadId)) {
                uploadId = this.fileMinioClient.initPartUpload(FileUtil.getFilePath("part", fileName), contentType);
            }

            // 上传文件分片，得到文件分片标识
            this.fileMinioClient.uploadPart(
                    index, uploadId, FileUtil.getFilePath("part", fileName), multipartFile.getInputStream());

            // 返回文件分片上传id
            InterviewUploadMaxFileAResp response = new InterviewUploadMaxFileAResp();
            response.setUploadId(uploadId);
            return response;
        } catch (Exception e) {
            log.error("InterviewService uploadMaxFile 大文件分片上传失败，失败原因 -> {}", e.getMessage());
            BaseExceptionUtil.throwException(BaseResponseEnum.ERROR_SERVICE, e.getMessage());
        } finally {
            try {
                lock.unlock();
            } catch (Exception e) {
                log.error("InterviewService uploadMaxFile 释放锁失败，失败原因 -> {}", e.getMessage());
            }
        }
        return null;
    }

    public InterviewUploadMaxFileAResp mergeMaxFile(InterviewMergeMaxFileAReq req) {
        try {
            String path = this.fileMinioClient.completePart(req.getUploadId(), FileUtil.getFilePath("part", req.getFileName()));
            InterviewUploadMaxFileAResp response = new InterviewUploadMaxFileAResp();
            response.setUrl(path);
            response.setUploadId(req.getUploadId());
            return response;
        } catch (Exception e) {
            log.error("InterviewService mergeMaxFile 分片文件合并失败，失败原因 -> {}", e.getMessage());
        }
        return null;
    }
}
